<template>
  <div>
    <div class="images_upload_wrap">
      <draggable
        class="custom_list_wrap"
        v-model="fileList"
        v-bind="dragOptions"
        @start="handleStartDrag"
        @end="handleEndDrag"
      >
        <transition-group name="imglist" tag="ul">
          <li
            class="demo-upload-list"
            v-for="item in fileList"
            :key="item.uid"
            :style="pictureStyle"
          >
            <i class="el-icon-loading" v-if="uploadLoading"></i>
            <img v-else :src="item.src" />
            <div class="demo-upload-list-cover">
              <el-button type="text" icon="el-icon-view" @click="handlePreview(item)" />
              <el-button v-if="!onlyView" type="text" icon="el-icon-delete" @click="handleRemove(item)" />
            </div>
          </li>
        </transition-group>
      </draggable>
      <el-upload
        v-if="isShowElUpload"
        drag
        class="el_upload_wrap"
        list-type="picture-card"
        :limit="uploadLimits"
        :name="paramName"
        :action="`${uploadBaseURL + uploadUrl}`"
        :multiple="multiple"
        :disabled="disabled"
        :data="uploadData"
        :accept="acceptFileTypes"
        :beforeUpload="handleBeforeUpload"
        :on-progress="handleProgress"
        :on-success="handleSuccess"
        :on-error="handleError"
        :on-exceed="handleExceed"
        :file-list="fileList"
        :show-file-list="false"
        :style="pictureStyle"
      >
        <el-button type="text" icon="el-icon-camera-solid" />
      </el-upload>
    </div>
    <p v-show="multiple && !onlyView" class="warn_color">提示：可以添加{{ uploadLimits }}张</p>
    <el-dialog title="大图展示" :visible.sync="previewImg.visible">
      <img width="100%" :src="previewImg.src" alt="">
    </el-dialog>
  </div>
</template>
<script>
import draggable from 'vuedraggable';
import { isResponseSuccess, generateUuid } from '@/utils/bizUtils';
export default {
  components: {
    draggable
  },
  props: {
    // 是否支持多选，默认单选
    multiple: {
      type: Boolean,
      default: false
    },
    // 是否禁用，默认不禁用
    disabled: {
      type: Boolean,
      default: false
    },
    // 上传时附带的额外参数，默认空对象
    uploadData: {
      type: Object,
      default: () => {}
    },
    // 接受上传的文件类型，默认jpeg,png,jpg
    acceptList: {
      type: Array,
      default: () => ['jpeg', 'png', 'jpg']
    },
    // 上传文件参数名，默认为myfile
    paramName: {
      type: String,
      default: 'myfile'
    },
    // 多选时，上传文件最大数量限制，默认5
    limit: {
      type: Number,
      default: 5
    },
    // 上传URL
    uploadUrl: {
      type: String,
      default: 'sysback/fileserver/upload'
    },
    defaultFileList: {
      type: Array,
      default: () => []
    },
    // 只是查看，默认可编辑
    onlyView: {
      type: Boolean,
      default: false
    }
  },
  data () {
    return {
      previewImg: {
        visible: false,
        src: ''
      },
      uploadLoading: false, // 上传loading
      fileList: [],
      showImgList: [],
      dragState: false,
      uploadFileNum: 0, // 上传的文件数量
      successFileNum: 0 // 已经上传成功的文件数量
    }
  },
  watch: {
    defaultFileList: {
      immediate: true,
      handler (val) {
        const files = this.initEchoFileList(val);
        this.fileList = this.getRecombineImgPath(files);
      }
    }
  },
  computed: {
    acceptFileTypes () {
      return this.acceptList.join(', ');
    },
    dragOptions () {
      return {
        animation: 200,
        group: 'description',
        disabled: false,
        ghostClass: 'ghost'
      };
    },
    // 图片样式
    pictureStyle () {
      const width = '120px';
      const height = '120px';
      const marginRight = '10px';
      return `width: ${width}; height: ${height}; margin-right: ${marginRight}; line-height: ${height}`;
    },
    uploadLimits () {
      if (this.multiple) return this.limit;
      return 1;
    },
    isShowElUpload () {
      return this.fileList.length < this.uploadLimits && !this.onlyView;
    },
  },
  methods: {
    initEchoFileList (list) {
      return list.map(url => ({ url, uid: generateUuid() }))
    },
    // 图片预览
    handlePreview (file) {
      this.previewImg.src = file.src;
      this.previewImg.visible = true;
    },
    // 图片删除
    handleRemove (file) {
      this.removeFileList(file);
      this.emitResults();
    },
    // 文件上传时的钩子
    handleProgress (event, file, fileList) {
      if (this.multiple) {
        this.fileList = fileList;
      } else {
        this.fileList = [file];
      }
      this.uploadFileNum++;
    },
    // 上传文件之前的钩子
    handleBeforeUpload (file) {
      if (this.isFailedCheckFileTypes(file)) return false;
      this.uploadLoading = true;
    },
    // 文件格式校验失败
    isFailedCheckFileTypes (file) {
      const fileType = file.name.substring(file.name.lastIndexOf('.') + 1);
      const hasCurrentType = this.acceptList.includes(fileType);
      if (!hasCurrentType) return this.$message.error('格式错误');
    },
    // 文件上传成功时的钩子
    handleSuccess (res, file) {
      this.uploadLoading = false;
      if (isResponseSuccess(res)) {
        this.fileList = this.getSuccessFileList(res, file);
        this.successFileNum++;
        console.log(this.successFileNum, this.uploadFileNum)
        if (this.successFileNum === this.uploadFileNum) this.emitResults();
      } else {
        this.removeFileList(file);
      }
    },
    // 文件上传失败时的钩子
    handleError (err, file) {
      this.uploadLoading = false;
      this.$message.error('上传失败');
      this.removeFileList(file);
    },
    // 文件超出个数限制时的钩子
    handleExceed (files, fileList) {
      const filesExceed = files.length > this.uploadLimits;
      const sumExceed = files.length + fileList.length > this.uploadLimits;
      if (filesExceed || sumExceed) {
        this.$message.warning(`最多只能上传${this.uploadLimits}张图片，请删除后再上传`);
      }
    },
    // 删除文件
    removeFileList (file) {
      this.fileList = this.fileList.filter(item => item?.uid !== file?.uid);
    },
    // 重组图片路径
    getRecombineImgPath (fileList) {
      const prefixUrl = this.IMAGEURL;
      const suffixUrl = this.XOSSPROCE;
      const reg = /^(http|https):\/\//;
      const noDuplicateList = _.cloneDeep(fileList).filter(item => item.url);
      const recombinedList = noDuplicateList.map(item => {
        if (!reg.test(item.url)) {
          item.src = `${prefixUrl}${item.url}?${suffixUrl}`;
          item.path = item?.response?.retData ?? item.url;
        }
        return item;
      });
      return recombinedList;
    },
    // 获取请求成功后的图片集合
    getSuccessFileList (res, file) {
      const [recombinePath] = this.getRecombineImgPath([{ ...file, url: res.retData }]);
      const filterList = this.fileList.filter(item => item.uid !== recombinePath.uid);
      return [...filterList, recombinePath];
    },
    // 获取图片基础路径集合
    getImgBasicPathList (list) {
      return list.map(item => item.path).filter(item => item);
    },
    // 开始拖拽
    handleStartDrag () {
      this.dragState = true;
    },
    // 结束拖拽
    handleEndDrag () {
      this.dragState = false;
      if (this.multiple) this.emitResults(); // 多选时才能拖拽列表
    },
    // 传送最终结果
    emitResults () {
      this.uploadFileNum = 0;
      this.successFileNum = 0;
      this.$emit('getFileList', this.getImgBasicPathList(this.fileList));
    }
  }
}
</script>
<style lang="less" scoped>
/deep/ .el-dialog__body {
  padding: 10px 20px;
}
/deep/ .el-dialog__header {
  border-bottom: 1px solid #e8eaec;
}

.images_upload_wrap {
  margin-bottom: 10px;
  display: inline-block;
}

/deep/ .el-upload--picture-card {
  border: 0px;
  line-height: 130px;
  .el-upload-dragger {
    width: 120px;
    height: 120px;
  }
}

.custom_list_wrap {
  float: left;
}

.demo-upload-list {
  display: inline-block;
  width: 60px;
  height: 60px;
  text-align: center;
  line-height: 60px;
  border: 1px solid transparent;
  border-radius: 4px;
  overflow: hidden;
  background: #fff;
  position: relative;
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
  margin-right: 4px;
  img {
    width: 100%;
    height: 100%;
  }
}
.demo-upload-list-cover {
  display: none;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background: rgba(0, 0, 0, 0.6);
  i {
    color: #fff;
    font-size: 20px;
    cursor: pointer;
    margin: 0 2px;
  }
}
.demo-upload-list:hover .demo-upload-list-cover {
  display: block;
}

.el_upload_wrap {
  display: inline-block;
}

/* 效果过程 */
.imglist-enter-active, .imglist-leave-active {
  transition: all 0.8s;
}
/* 进场的瞬间与离场的效果添加 */
.imglist-enter, .imglist-leave-to {
  opacity: 0;
  transform: translateX(30px);
}
</style>
